package carassius.BLL.Events;

import carassius.BLL.Events.Object.Added.ObjectAddedListener;
import carassius.BLL.Events.Object.Added.ObjectAddedPublisher;
import carassius.BLL.Events.Object.ObjectEvent;
import carassius.BLL.Events.Object.Removed.ObjectRemovedListener;
import carassius.BLL.Events.Object.Removed.ObjectRemovedPublisher;
import java.util.ArrayList;
import java.util.Collection;

/**
 *
 * @author siebz0r
 */
public class ArrayListWithEvents<E>
		extends ArrayList<E>
		implements ObjectAddedPublisher,
				   ObjectRemovedPublisher
{
	private ArrayList<ObjectAddedListener> _objectAddedListeners;
	private ArrayList<ObjectRemovedListener> _objectRemovedListeners;

	@Override
	public boolean add(E e)
	{
		if (super.add(e))
		{
			fireObjectAddedEvent(e);
			return true;
		}
		return false;
	}

	@Override
	public void add(int index, E element)
	{
		add(element);
	}

	@Override
	public boolean addAll(Collection<? extends E> c)
	{
		int pre = size();
		for (E o : c)
		{
			add(o);
		}
		return (pre != size());
	}

	@Override
	public boolean addAll(int index,
						  Collection<? extends E> c)
	{
		return addAll(c);
	}

	@Override
	public boolean remove(Object o)
	{
		if (super.remove(o))
		{
			fireObjectRemovedEvent((E)o);
			return true;
		}
		return false;
	}

	@Override
	public E remove(int index)
	{
		E o = get(index);
		if (o != null)
		{
			remove(index);
			fireObjectRemovedEvent(o);
		}
		return o;
	}

	@Override
	public boolean removeAll(Collection<?> c)
	{
		int pre = size();
		if (c != null)
		{
			for (Object o : c)
			{
				remove(o);
			}
		}
		return (pre != size());
	}

	@Override
	protected void removeRange(int fromIndex, int toIndex)
	{
		if (fromIndex >= 0
				&& fromIndex < toIndex
				&& toIndex <= size()-1)
		{
			ArrayList<E> removeQueue = new ArrayList<E>(toIndex-fromIndex+1);
			for (int i = fromIndex; i <= toIndex; i++)
			{
				removeQueue.add(get(i));
			}
			for (E o : removeQueue)
			{
				remove(o);
			}
		}
	}

	@Override
	public void clear()
	{
		for (E o : this)
		{
			fireObjectRemovedEvent(o);
		}
		super.clear();
	}

	@Override
	public E set(int index, E element)
	{
		throw new UnsupportedOperationException();
	}

	@Override
	public void addObjectAddedListener(ObjectAddedListener listener)
	{
		if (_objectAddedListeners == null)
		{
			_objectAddedListeners = new ArrayList<ObjectAddedListener>();
		}
		_objectAddedListeners.add(listener);
	}

	@Override
	public void removeObjectAddedListener(ObjectAddedListener listener)
	{
		if (_objectAddedListeners != null)
		{
			_objectAddedListeners.remove(listener);
		}
	}

	private void fireObjectAddedEvent(E obj)
	{
		if (_objectAddedListeners != null)
		{
			ObjectEvent evt = new ObjectEvent(obj, this);
			for (ObjectAddedListener listener : _objectAddedListeners)
			{
				listener.objectAdded(evt);
			}
		}
	}

	@Override
	public void addObjectRemovedListener(ObjectRemovedListener listener)
	{
		if (_objectRemovedListeners == null)
		{
			_objectRemovedListeners = new ArrayList<ObjectRemovedListener>();
		}
		_objectRemovedListeners.add(listener);
	}

	@Override
	public void removeObjectRemovedListener(ObjectRemovedListener listener)
	{
		if (_objectRemovedListeners != null)
		{
			_objectRemovedListeners.remove(listener);
		}
	}

	private void fireObjectRemovedEvent(E obj)
	{
		if (_objectRemovedListeners != null)
		{
			ObjectEvent evt = new ObjectEvent(obj, this);
			for (ObjectRemovedListener listener : _objectRemovedListeners)
			{
				listener.objectRemoved(evt);
			}
		}
	}
}
